//////////////////////////////////////////////////////////////////////////
#include "CxTypes.Structs.h"
#include "Cv.Enums.h"
#include "NativeHandleObject.h"
#include "CvInvoke.Managed.Helper.h"
//////////////////////////////////////////////////////////////////////////
#pragma once
#pragma managed
//////////////////////////////////////////////////////////////////////////
NAMESPACE_BEGIN
//////////////////////////////////////////////////////////////////////////
public ref class ManagedArr abstract: public NativeHandleObject
{
protected:
	virtual void ReleaseHandle() override
	{
	}

	ManagedArr(CvArr* handle, bool own) : NativeHandleObject(handle, own)
	{

	}

	ManagedArr(bool own) : NativeHandleObject(own)
	{

	}

internal:
	CvArr* ToCvArrPointer()
	{
		return (CvArr*)m_pHandle;
	}
};

public ref class ManagedImage : public ManagedArr
{
public:
	static property ManagedImage^ Empty
	{
		ManagedImage^ get() { return gcnew ManagedImage(NULL, false); }
	}

public:
	ManagedImage(Size2D32s size, PixelDepth depth, int channels) : ManagedArr(NULL, true)
	{
		Attach(cvCreateImage(*(CvSize*)&size, (int)depth, (int)channels));
	}

	PROPERTY_READONLY(PixelDepth, Depth, IplImage, depth)
	PROPERTY_READONLY(int, Width, IplImage, width)
	PROPERTY_READONLY(int, Height, IplImage, height)
	PROPERTY_READONLY(int, Channels, IplImage, nChannels)
	PROPERTY_READONLY(ImageAlign, Align, IplImage, align)
	PROPERTY_READONLY(ImageDataOrder, DataOrder, IplImage, dataOrder)
	PROPERTY_READONLY(ImageOrigin, Origin, IplImage, origin)
	PROPERTY_READONLY(int, Stride, IplImage, widthStep)
	PROPERTY_READONLY(int, ImageSize, IplImage, imageSize)
	PROPERTY_READONLY_PTR(Scan0, IplImage, imageData)

protected:
	virtual void ReleaseHandle() override
	{
		IplImage* pImage = this->ToIplImagePointer();
		cvReleaseImage(&pImage);
		m_pHandle = pImage;
	}

internal:
	ManagedImage(IplImage* handle, bool own) : ManagedArr(handle, own)
	{
	}

	IplImage* ToIplImagePointer()
	{
		return (IplImage*)m_pHandle;
	}
};

public ref class ManagedConvKernel : public NativeHandleObject
{
public:
	ManagedConvKernel(int cols, int rows, int anchor_x, int anchor_y, ShapeType shape) : NativeHandleObject(true)
	{
		Attach(cvCreateStructuringElementEx(cols, rows, anchor_x, anchor_y, (int)shape));
	}

	ManagedConvKernel(int cols, int rows, int anchor_x, int anchor_y, ShapeType shape, array<int>^ values) : NativeHandleObject(true)
	{
		pin_ptr<int> pvalues = &values[0];
		Attach(cvCreateStructuringElementEx(cols, rows, anchor_x, anchor_y, (int)shape, pvalues));
	}

	PROPERTY_READONLY(int, Cols, IplConvKernel, nCols)
	PROPERTY_READONLY(int, Rows, IplConvKernel, nRows)
	PROPERTY_READONLY(int, AnchorX, IplConvKernel, anchorX)
	PROPERTY_READONLY(int, AnchorY, IplConvKernel, anchorY)
	PROPERTY_READONLY(int, ShiftR, IplConvKernel, nShiftR)

	property int default[int, int]
	{
		int get(int row, int col)
		{
			IplConvKernel* pkernel = this->ToIplConvKernelPointer();
			return pkernel->values[row * pkernel->nCols + col];
		}
		void set(int row, int col, int value)
		{
			IplConvKernel* pkernel = this->ToIplConvKernelPointer();
			pkernel->values[row * pkernel->nCols + col] = value;
		}
	}

protected:
	virtual void ReleaseHandle() override
	{
		IplConvKernel* pkernel = this->ToIplConvKernelPointer();
		cvReleaseStructuringElement(&pkernel);
		m_pHandle = pkernel;
	}

internal:
	ManagedConvKernel(IplConvKernel* handle, bool own) : NativeHandleObject(handle, own)
	{
	}

	inline IplConvKernel* ToIplConvKernelPointer()
	{
		return (IplConvKernel*)m_pHandle;
	}
};

public ref class ManagedMat : public ManagedArr
{
public:
	static property ManagedMat^ Empty
	{
		ManagedMat^ get() { return gcnew ManagedMat(NULL, false); }
	}

public:
	ManagedMat(int rows, int cols, MatFlag type) : ManagedArr(true)
	{
		Attach(cvCreateMat(rows, cols, (int)type));
	}

	PROPERTY_READONLY(MatFlag, Type, CvMat, type)
	PROPERTY_READONLY(int, Width, CvMat, width)
	PROPERTY_READONLY(int, Height, CvMat, height)
	PROPERTY_READONLY(int, Rows, CvMat, rows)
	PROPERTY_READONLY(int, Cols, CvMat, cols)
	PROPERTY_READONLY(int, Stride, CvMat, step)
	PROPERTY_READONLY_PTR(Scan0, CvMat, data.ptr)

protected:
	virtual void ReleaseHandle() override
	{
		CvMat* pMat = this->ToCvMatPointer();
		cvReleaseMat(&pMat);
		m_pHandle = pMat;
	}

internal:
	ManagedMat(CvMat* handle, bool own) : ManagedArr(handle, own)
	{

	}

	CvMat* ToCvMatPointer()
	{
		return (CvMat*)m_pHandle;
	}
};

public ref class ManagedMatND : public ManagedArr
{
public:
	static property ManagedMatND^ Empty
	{
		ManagedMatND^ get() { return gcnew ManagedMatND(NULL, false); }
	}

public:
	ManagedMatND(int dims, array<int>^ sizes, MatFlag type) : ManagedArr(true)
	{
		pin_ptr<int> psizes = &sizes[0];
		Attach(cvCreateMatND(dims, psizes, (int)type));
	}

	PROPERTY_READONLY(MatFlag, Type, CvMatND, type)
	PROPERTY_READONLY(int, Dims, CvMatND, dims)
	PROPERTY_READONLY_PTR(Scan0, CvMatND, data.ptr)

	property array<MatNDDim>^ DimPairs
	{
		array<MatNDDim>^ get()
		{
			CvMatND* pMat = this->ToCvMatNDPointer();
			array<MatNDDim>^ dims = gcnew array<MatNDDim>(pMat->dims);
			for (int i = 0; i < pMat->dims; i++)
			{
				dims[i] = *(MatNDDim*)&(pMat->dim[i]);
			}
			return dims;
		}
	}

	property array<int>^ Sizes
	{
		array<int>^ get()
		{
			CvMatND* pMat = this->ToCvMatNDPointer();
			array<int>^ sizes = gcnew array<int>(pMat->dims);
			for (int i = 0; i < pMat->dims; i++)
			{
				sizes[i] = pMat->dim[i].size;
			}
			return sizes;
		}
	}

	property array<int>^ Steps
	{
		array<int>^ get()
		{
			CvMatND* pMat = this->ToCvMatNDPointer();
			array<int>^ sizes = gcnew array<int>(pMat->dims);
			for (int i = 0; i < pMat->dims; i++)
			{
				sizes[i] = pMat->dim[i].step;
			}
			return sizes;
		}
	}

protected:
	virtual void ReleaseHandle() override
	{
		CvMatND* pMat = this->ToCvMatNDPointer();
		cvReleaseMatND(&pMat);
		m_pHandle = pMat;
	}

internal:
	ManagedMatND(CvMatND* handle, bool own) : ManagedArr(handle, own)
	{

	}

	inline CvMatND* ToCvMatNDPointer()
	{
		return (CvMatND*)m_pHandle;
	}
};

public ref class ManagedSparseMat : public ManagedArr
{
public:
	ManagedSparseMat(int dims, array<int>^ sizes, MatFlag type) : ManagedArr(true)
	{
		pin_ptr<int> psizes = &sizes[0];
		Attach(cvCreateSparseMat(dims, psizes, (int)type));
	}

	PROPERTY_READONLY(MatFlag, Type, CvSparseMat, type)
	PROPERTY_READONLY(int, Dims, CvSparseMat, dims)

protected:
	virtual void ReleaseHandle() override
	{
		CvSparseMat* pMat = this->ToCvSparseMatPointer();
		cvReleaseSparseMat(&pMat);
		m_pHandle = pMat;
	}

internal:
	ManagedSparseMat(CvSparseMat* handle, bool own) : ManagedArr(handle, own)
	{

	}

	inline CvSparseMat* ToCvSparseMatPointer()
	{
		return (CvSparseMat*)m_pHandle;
	}
};

public ref class ManagedSparseNode : public NativeHandleObject
{
private:
	ManagedSparseNode() : NativeHandleObject(false) {}

	PROPERTY_READONLY(unsigned int, HashVal, CvSparseNode, hashval)
	PROPERTY_READONLY_NATIVE_HANDLE(ManagedSparseNode, Next, CvSparseNode, next)

protected:
	virtual void ReleaseHandle() override
	{
	}

internal:
	ManagedSparseNode(CvSparseNode* handle) : NativeHandleObject(handle, false)
	{

	}

	inline CvSparseNode* ToCvSparseNodePointer()
	{
		return (CvSparseNode*)m_pHandle;
	}
};

public ref class ManagedSparseMatIterator : public NativeHandleObject
{
public:
	ManagedSparseMatIterator() : NativeHandleObject(new CvSparseMatIterator(), true)
	{
	}

	PROPERTY_READONLY_NATIVE_HANDLE_EX(ManagedSparseMat, Mat, CvSparseMatIterator, mat, false)
	PROPERTY_READONLY_NATIVE_HANDLE(ManagedSparseNode, Node, CvSparseMatIterator, node)

protected:
	virtual void ReleaseHandle() override
	{
		delete (CvSparseMatIterator*)m_pHandle;
	}

internal:
	inline CvSparseMatIterator* ToCvSparseMatIteratorPointer()
	{
		return (CvSparseMatIterator*)m_pHandle;
	}
};

public ref class ManagedHistogram : public NativeHandleObject
{
public:
	/// <summary>
	/// Creates new histogram
	/// </summary>
	/// <param name="dims"></param>
	/// <param name="sizes"></param>
	/// <param name="type"></param>
	/// <param name="ranges"></param>
	/// <returns></returns>
	ManagedHistogram(int dims, array<int>^ sizes, HistType type, array<float, 2>^ ranges, bool uniform) : NativeHandleObject(true)
	{
		pin_ptr<int> psizes = &sizes[0];
		pin_ptr<float> pranges = &ranges[0, 0];
		Attach(cvCreateHist(dims, psizes, (int)type, (float**)pranges, (int)uniform));
	}

	/// <summary>
	/// Creates new histogram
	/// </summary>
	/// <param name="dims"></param>
	/// <param name="sizes"></param>
	/// <param name="type"></param>
	/// <returns></returns>
	ManagedHistogram(int dims, array<int>^ sizes, HistType type, array<float, 2>^ ranges) : NativeHandleObject(true)
	{
		pin_ptr<int> psizes = &sizes[0];
		pin_ptr<float> pranges = &ranges[0, 0];
		Attach(cvCreateHist(dims, psizes, (int)type, (float**)pranges));
	}

	/// <summary>
	/// Creates new histogram
	/// </summary>
	/// <param name="dims"></param>
	/// <param name="sizes"></param>
	/// <returns></returns>
	ManagedHistogram(int dims, array<int>^ sizes, HistType type) : NativeHandleObject(true)
	{
		pin_ptr<int> psizes = &sizes[0];
		Attach(cvCreateHist(dims, psizes, (int)type));
	}

	/// <summary>
	/// Assignes histogram bin ranges
	/// </summary>
	/// <param name="hist"></param>
	/// <param name="ranges"></param>
	void SetHistBinRanges(array<float, 2>^ ranges, bool uniform)
	{
		pin_ptr<float> pranges = &ranges[0, 0];
		cvSetHistBinRanges(this->ToCvHistogramPointer(), (float**)pranges, (int)uniform);
	}

	/// <summary>
	/// Assignes histogram bin ranges
	/// </summary>
	/// <param name="hist"></param>
	void SetHistBinRanges(array<float, 2>^ ranges)
	{
		pin_ptr<float> pranges = &ranges[0, 0];
		cvSetHistBinRanges(this->ToCvHistogramPointer(), (float**)pranges);
	}

	PROPERTY_READONLY(HistType, Type, CvHistogram, type)
	
	property ManagedArr^ Bins
	{
		ManagedArr^ get()
		{
			CvHistogram* pHistogram = this->ToCvHistogramPointer();
			if ((CV_IS_SPARSE_HIST(pHistogram)))
			{
				return gcnew ManagedSparseMat((CvSparseMat*)pHistogram->bins, false);
			}
			else
			{
				return gcnew ManagedMatND(&(pHistogram->mat),false); 
			}
		}
	}

	property bool HasRanges
	{
		bool get()
		{
			return CV_HIST_HAS_RANGES(this->ToCvHistogramPointer());
		}
	}

	property bool IsSparse
	{
		bool get()
		{
			return CV_IS_SPARSE_HIST(this->ToCvHistogramPointer());
		}
	}

protected:
	virtual void ReleaseHandle() override
	{
		CvHistogram* pHistogram = this->ToCvHistogramPointer();
		cvReleaseHist(&pHistogram);
		m_pHandle = pHistogram;
	}

internal:
	ManagedHistogram(CvHistogram* handle, bool own) : NativeHandleObject(handle, own)
	{
	}

	inline CvHistogram* ToCvHistogramPointer()
	{
		return (CvHistogram*)m_pHandle;
	}
};

public ref class ManagedLineIterator : public NativeHandleObject
{
public:
	ManagedLineIterator() : NativeHandleObject(new CvLineIterator(), true)
	{

	}

	PROPERTY_READONLY_PTR(CurrentPointPtr, CvLineIterator, ptr)

protected:
	virtual void ReleaseHandle() override
	{
		delete m_pHandle;
	}

internal:
	inline CvLineIterator* ToCvLineIteratorPointer()
	{
		return (CvLineIterator*)m_pHandle;
	}
};

public ref class ManagedMemBlock : public NativeHandleObject
{
private:
	ManagedMemBlock() : NativeHandleObject(false) {}

public:
	PROPERTY_READONLY_NATIVE_HANDLE(ManagedMemBlock, Prev, CvMemBlock, prev)
	PROPERTY_READONLY_NATIVE_HANDLE(ManagedMemBlock, Next, CvMemBlock, next)

protected:
	virtual void ReleaseHandle() override
	{
	}

internal:
	ManagedMemBlock(CvMemBlock* handle) : NativeHandleObject(handle, false)
	{

	}

	inline CvMemBlock* ToCvMemBlockPointer()
	{
		return (CvMemBlock*)m_pHandle;
	}
};

public ref class ManagedMemStorage : public NativeHandleObject
{
public:
	/// <summary>
	/// Creates new memory storage.
	/// block_size == 0 means that default,
	/// somewhat optimal size, is used (currently, it is 64K)
	/// </summary>
	/// <returns></returns>
	ManagedMemStorage(int block_size) : NativeHandleObject(true)
	{
		Attach(cvCreateMemStorage(block_size));
	}

	/// <summary>
	/// Creates new memory storage.
	/// block_size == 0 means that default,
	/// somewhat optimal size, is used (currently, it is 64K)
	/// </summary>
	/// <returns></returns>
	ManagedMemStorage() : NativeHandleObject(true)
	{
		Attach(cvCreateMemStorage());
	}

protected:
	virtual void ReleaseHandle() override
	{
		CvMemStorage* pMemStorage = this->ToCvMemStoragePointer();
		cvReleaseMemStorage(&pMemStorage);
		m_pHandle = pMemStorage;
	}

internal:
	ManagedMemStorage(CvMemStorage* handle, bool own) : NativeHandleObject(handle, own)
	{

	}

	inline CvMemStorage* ToCvMemStoragePointer()
	{
		return (CvMemStorage*)m_pHandle;
	}
};

public ref class ManagedMemStoragePos : public NativeHandleObject
{
public:
	ManagedMemStoragePos() : NativeHandleObject(new CvMemStoragePos(), true)
	{
	}

protected:
	virtual void ReleaseHandle() override
	{
		delete (CvMemStoragePos*)m_pHandle;
	}

internal:
	inline CvMemStoragePos* ToCvMemStoragePosPointer()
	{
		return (CvMemStoragePos*)m_pHandle;
	}
};

public ref class ManagedSeqBlock : public NativeHandleObject
{
public:
	ManagedSeqBlock() : NativeHandleObject(new CvSeqBlock(), true)
	{

	}

protected:
	virtual void ReleaseHandle() override
	{
		delete (CvSeqBlock*)m_pHandle;
	}

internal:
	inline CvSeqBlock* ToCvSeqBlockPointer()
	{
		return (CvSeqBlock*)m_pHandle;
	}
};

public ref class ManagedSeq : public ManagedArr
{
public:
	ManagedSeq(SeqFlag seq_flags, int header_size, int elem_size, ManagedMemStorage^ storage) : ManagedArr(false)
	{
		Attach(cvCreateSeq((int)seq_flags, header_size, elem_size, storage->ToCvMemStoragePointer()));
	}

protected:
	virtual void ReleaseHandle() override
	{
	}

public:
	PROPERTY_READONLY(SeqFlag, Flags, CvSeq, flags)
	PROPERTY_READONLY_NATIVE_HANDLE(ManagedSeq, HPrev, CvSeq, h_prev);
	PROPERTY_READONLY_NATIVE_HANDLE(ManagedSeq, HNext, CvSeq, h_next);
	PROPERTY_READONLY_NATIVE_HANDLE(ManagedSeq, VPrev, CvSeq, v_prev);
	PROPERTY_READONLY_NATIVE_HANDLE(ManagedSeq, VNext, CvSeq, v_next);

internal:
	ManagedSeq(CvSeq* handle) : ManagedArr(handle, false)
	{

	}

	inline CvSeq* ToCvSeqPointer()
	{
		return (CvSeq*)m_pHandle;
	}
};

public ref class ManagedSet : public NativeHandleObject
{
protected:
	virtual void ReleaseHandle() override
	{
	}

internal:
	ManagedSet(CvSet* handle) : NativeHandleObject(handle, false)
	{

	}

	inline CvSet* ToCvSetPointer()
	{
		return (CvSet*)m_pHandle;
	}
};

public ref class ManagedSetElem : public NativeHandleObject
{
protected:
	virtual void ReleaseHandle() override
	{
	}

internal:
	ManagedSetElem(CvSetElem* handle) : NativeHandleObject(handle, false)
	{
	}

	inline CvSetElem* ToCvSetElemPointer()
	{
		return (CvSetElem*)m_pHandle;
	}
};

public ref class ManagedGraphVtx : public NativeHandleObject
{
protected:
	virtual void ReleaseHandle() override
	{
	}

internal:
	ManagedGraphVtx(CvGraphVtx* handle) : NativeHandleObject(handle, false)
	{
	}

	inline CvGraphVtx* ToCvGraphVtxPointer()
	{
		return (CvGraphVtx*)m_pHandle;
	}
};

public ref class ManagedGraphVtx2D : public NativeHandleObject
{
protected:
	virtual void ReleaseHandle() override
	{
	}

internal:
	ManagedGraphVtx2D(CvGraphVtx2D* handle) : NativeHandleObject(handle, false)
	{
	}

	inline CvGraphVtx2D* ToCvGraphVtx2DPointer()
	{
		return (CvGraphVtx2D*)m_pHandle;
	}
};

public ref class ManagedGraphEdge : public NativeHandleObject
{
protected:
	virtual void ReleaseHandle() override
	{
	}

internal:
	ManagedGraphEdge(CvGraphEdge* handle) : NativeHandleObject(handle, false)
	{

	}

	inline CvGraphEdge* ToCvGraphEdgePointer()
	{
		return (CvGraphEdge*)m_pHandle;
	}
};

public ref class ManagedGraph : public NativeHandleObject
{
protected:
	virtual void ReleaseHandle() override
	{
	}

internal:
	ManagedGraph(CvGraph* handle) : NativeHandleObject(handle, false)
	{

	}

	inline CvGraph* ToCvGraphPointer()
	{
		return (CvGraph*)m_pHandle;
	}
};

public ref class ManagedChain : public NativeHandleObject
{
protected:
	virtual void ReleaseHandle() override
	{
	}

internal:
	ManagedChain(CvChain* handle) : NativeHandleObject(handle, false)
	{

	}

	inline CvChain* ToCvChainPointer()
	{
		return (CvChain*)m_pHandle;
	}
};

public ref class ManagedContour : public NativeHandleObject
{
protected:
	virtual void ReleaseHandle() override
	{
	}

internal:
	ManagedContour(CvContour* handle) : NativeHandleObject(handle, false)
	{

	}

	inline CvContour* ToCvContourPointer()
	{
		return (CvContour*)m_pHandle;
	}
};

public ref class ManagedPoint2DSeq : public NativeHandleObject
{
protected:
	virtual void ReleaseHandle() override
	{
	}

internal:
	ManagedPoint2DSeq(CvPoint2DSeq* handle) : NativeHandleObject(handle, false)
	{

	}

	inline CvPoint2DSeq* ToCvPoint2DSeqPointer()
	{
		return (CvPoint2DSeq*)m_pHandle;
	}
};

public ref class ManagedSeqWriter : public NativeHandleObject
{
public:
	ManagedSeqWriter() : NativeHandleObject(new CvSeqWriter(), true)
	{
	}

protected:
	virtual void ReleaseHandle() override
	{
		delete (CvSeqWriter*)m_pHandle;
	}

internal:
	inline CvSeqWriter* ToCvSeqWriterPointer()
	{
		return (CvSeqWriter*)m_pHandle;
	}
};

public ref class ManagedSeqReader : public NativeHandleObject
{
public:
	ManagedSeqReader() : NativeHandleObject(new CvSeqReader(), true)
	{

	}

protected:
	virtual void ReleaseHandle() override
	{
		delete (CvSeqReader*)m_pHandle;
	}

internal:
	inline CvSeqReader* ToCvSeqReaderPointer()
	{
		return (CvSeqReader*)m_pHandle;
	}
};

public ref class ManagedFileStorage : public NativeHandleObject
{
protected:
	virtual void ReleaseHandle() override
	{
		CvFileStorage* pFileStorage = this->ToCvFileStoragePointer();
		cvReleaseFileStorage(&pFileStorage);
		this->m_pHandle = pFileStorage;
	}

internal:
	ManagedFileStorage(CvFileStorage* handle, bool own) : NativeHandleObject(handle, own)
	{

	}

	inline CvFileStorage* ToCvFileStoragePointer()
	{
		return (CvFileStorage*)m_pHandle;
	}
};

public ref class ManagedFileNode : public NativeHandleObject
{
protected:
	virtual void ReleaseHandle() override
	{
	}

internal:
	ManagedFileNode(CvFileNode* handle, bool own) : NativeHandleObject(handle, own)
	{

	}

	inline CvFileNode* ToCvFileNodePointer()
	{
		return (CvFileNode*)m_pHandle;
	}
};

public ref class ManagedAttrList : public NativeHandleObject
{
protected:
	virtual void ReleaseHandle() override
	{
	}

internal:
	ManagedAttrList(CvAttrList* handle, bool own) : NativeHandleObject(handle, own)
	{

	}

	inline CvAttrList* ToCvAttrListPointer()
	{
		return (CvAttrList*)m_pHandle;
	}
};

//////////////////////////////////////////////////////////////////////////
NAMESPACE_END
//////////////////////////////////////////////////////////////////////////